import tkinter as tk
from tkinter import filedialog, messagebox
from docx import Document
from docx.shared import Inches, Cm
from PIL import Image
import os
import json

class ImageToWordApp:
    def __init__(self, root):
        self.root = root
        self.root.title("图片转Word工具")
        self.root.geometry("600x400")
        
        # 设置文件路径
        self.settings_file = os.path.join(os.path.dirname(__file__), "settings.json")
        
        # 初始化基本变量 - 在任何UI创建之前完成
        self.aspect_ratio = 200/150  # 默认比例
        self.last_width = 150
        self.last_height = 200
        self.aspect_var = tk.BooleanVar(value=True)  # 初始化aspect_var
        
        # 创建主框架
        self.main_frame = tk.Frame(self.root, padx=20, pady=20)
        self.main_frame.pack(expand=True, fill='both')
        
        # 创建UI元素和菜单
        self.setup_ui()
        self.create_menu()
        
        # 绑定窗口关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        
        # 加载保存的设置
        self.load_settings()

    def init_variables(self):
        """初始化所有变量"""
        self.aspect_ratio = 200/150  # 默认比例
        self.last_width = 150
        self.last_height = 200
        self.aspect_var = tk.BooleanVar(value=True)  # 初始化aspect_var

    def setup_ui(self):
        """创建UI元素"""
        self.setup_source_frame()
        self.setup_target_frame()
        self.setup_size_frame()
        self.setup_convert_frame()

    def create_menu(self):
        """创建菜单栏"""
        self.menubar = tk.Menu(self.root)
        self.root.config(menu=self.menubar)
        
        # 文件菜单
        file_menu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="文件", menu=file_menu)
        file_menu.add_command(label="选择图片文件夹", command=self.choose_source)
        file_menu.add_command(label="选择保存位置", command=self.choose_target)
        file_menu.add_separator()
        file_menu.add_command(label="开始转换", command=self.start_convert)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.on_closing)
        
        # 设置菜单
        settings_menu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="设置", menu=settings_menu)
        settings_menu.add_checkbutton(label="锁定纵横比", variable=self.aspect_var)
        settings_menu.add_separator()
        settings_menu.add_command(label="重置默认设置", command=self.reset_settings)
        
        # 帮助菜单
        help_menu = tk.Menu(self.menubar, tearoff=0)
        self.menubar.add_cascade(label="帮助", menu=help_menu)
        help_menu.add_command(label="使用说明", command=self.show_help)
        help_menu.add_command(label="关于", command=self.show_about)

    def setup_source_frame(self):
        """设置源文件夹选择框架"""
        self.source_frame = tk.Frame(self.main_frame)
        self.source_frame.pack(fill='x', pady=10)
        
        self.source_label = tk.Label(self.source_frame, text="图片文件夹：")
        self.source_label.pack(side='left')
        
        self.source_entry = tk.Entry(self.source_frame)
        self.source_entry.pack(side='left', expand=True, fill='x', padx=5)
        
        self.source_button = tk.Button(self.source_frame, text="浏览", command=self.choose_source)
        self.source_button.pack(side='right')

    def setup_target_frame(self):
        """设置目标文件选择框架"""
        self.target_frame = tk.Frame(self.main_frame)
        self.target_frame.pack(fill='x', pady=10)
        
        self.target_label = tk.Label(self.target_frame, text="保存文件为：")
        self.target_label.pack(side='left')
        
        self.target_entry = tk.Entry(self.target_frame)
        self.target_entry.pack(side='left', expand=True, fill='x', padx=5)
        
        self.target_button = tk.Button(self.target_frame, text="浏览", command=self.choose_target)
        self.target_button.pack(side='right')

    def setup_size_frame(self):
        """设置尺寸控制框架"""
        self.size_frame = tk.Frame(self.main_frame)
        self.size_frame.pack(fill='x', pady=10)
        
        # 宽度输入
        self.width_label = tk.Label(self.size_frame, text="最大宽度(mm)：")
        self.width_label.pack(side='left')
        
        self.width_entry = tk.Entry(self.size_frame, width=10)
        self.width_entry.pack(side='left', padx=5)
        self.width_entry.insert(0, str(self.last_width))
        self.width_entry.bind('<KeyRelease>', self.update_height)
        
        # 高度输入
        self.height_label = tk.Label(self.size_frame, text="最大高度(mm)：")
        self.height_label.pack(side='left', padx=(20, 0))
        
        self.height_entry = tk.Entry(self.size_frame, width=10)
        self.height_entry.pack(side='left', padx=5)
        self.height_entry.insert(0, str(self.last_height))
        self.height_entry.bind('<KeyRelease>', self.update_width)
        
        # 锁定比例选项 - 使用已初始化的aspect_var
        self.aspect_check = tk.Checkbutton(self.size_frame, text="锁定纵横比", variable=self.aspect_var)
        self.aspect_check.pack(side='right')

    def setup_convert_frame(self):
        """设置转换按钮和状态显示"""
        # 创建一个框架来容纳按钮和状态标签
        self.convert_frame = tk.Frame(self.main_frame)
        self.convert_frame.pack(fill='x', pady=10)
        
        # 转换按钮
        self.convert_button = tk.Button(self.convert_frame, text="开始转换", command=self.start_convert)
        self.convert_button.pack(pady=10)
        
        # 状态标签 - 使用自动换行和更大的显示区域
        self.status_label = tk.Label(self.convert_frame, text="准备就绪", font=('宋体', 10), relief='sunken', bd=1, wraplength=550, justify='left', padx=10, pady=5, height=3)
        self.status_label.pack(fill='x', pady=5)  # 水平填充

    def update_status(self, message):
        """更新状态信息"""
        self.status_label.config(text=message)
        self.root.update()

    def choose_source(self):
        """选择源文件夹"""
        folder = filedialog.askdirectory()
        if folder:
            self.source_entry.delete(0, tk.END)
            self.source_entry.insert(0, folder)
            
            # 统计图片数量
            image_count = 0
            if os.path.isdir(folder):
                image_files = [f for f in os.listdir(folder) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))]
                image_count = len(image_files)
            
            # 更新状态信息，包含图片数量
            self.update_status(f"已选择源文件夹: {folder}\n共发现 {image_count} 张图片")
            
            # 自动设置目标文件路径
            default_save_path = os.path.join(folder, "供打印的水印图片.docx")
            self.target_entry.delete(0, tk.END)
            self.target_entry.insert(0, default_save_path)
        else:
            self.update_status("取消选择源文件夹")

    def choose_target(self):
        """选择目标文件"""
        # 获取源文件夹路径作为默认保存路径
        default_dir = self.source_entry.get()
        if not default_dir or not os.path.isdir(default_dir):
            default_dir = os.path.expanduser("~")  # 如果没有选择源文件夹或路径无效，则使用用户主目录
            
        file = filedialog.asksaveasfilename(
            defaultextension=".docx", 
            filetypes=[("Word文档", "*.docx")],
            initialfile="供打印的水印图片.docx",
        )
        if file:
            self.target_entry.delete(0, tk.END)
            self.target_entry.insert(0, file)
            self.update_status(f"已选择保存位置: {file}")
        else:
            self.update_status("取消选择保存位置")

    def update_height(self, event=None):
        """更新高度值"""
        if self.aspect_var.get():
            try:
                width = float(self.width_entry.get())
                new_height = width * self.aspect_ratio
                self.height_entry.delete(0, tk.END)
                self.height_entry.insert(0, f"{new_height:.1f}")
            except ValueError:
                pass

    def update_width(self, event=None):
        """更新宽度值"""
        if self.aspect_var.get():
            try:
                height = float(self.height_entry.get())
                new_width = height / self.aspect_ratio
                self.width_entry.delete(0, tk.END)
                self.width_entry.insert(0, f"{new_width:.1f}")
            except ValueError:
                pass

    def start_convert(self):
        """开始转换流程"""
        source_folder = self.source_entry.get()
        target_file = self.target_entry.get()
        
        # 输入验证
        if not source_folder or not target_file:
            messagebox.showerror("错误", "请选择图片文件夹和保存位置！")
            return
            
        try:
            # 获取并验证尺寸输入
            width = float(self.width_entry.get())
            height = float(self.height_entry.get())
            self.aspect_ratio = height / width
            
            # 转换单位
            max_width = width / 25.4
            max_height = height / 25.4
            
        except ValueError:
            messagebox.showerror("错误", "请输入有效的宽度和高度数值！")
            return
            
        # 开始转换过程
        try:
            self.status_label.config(text="正在转换...")
            self.root.update()
            
            doc = Document()
            
            # 设置文档为横向方向和页边距
            from docx.shared import Cm
            from docx.enum.section import WD_ORIENT
            sections = doc.sections
            for section in sections:
                section.orientation = WD_ORIENT.LANDSCAPE  # 设置为横向
                section.page_width, section.page_height = section.page_height, section.page_width  # 交换高度和宽度
                
                # 设置页边距为0.5厘米(更小的页边距)
                section.left_margin = Cm(0.5)
                section.right_margin = Cm(0.5)
                section.top_margin = Cm(1)
                section.bottom_margin = Cm(1)
            
            self.process_images(source_folder, doc, max_width, max_height)
            
            doc.save(target_file)
            self.status_label.config(text="转换完成！")
            messagebox.showinfo("成功", f"文档已保存为：{target_file}")
            
            # 保存当前设置
            self.save_settings()
            
        except Exception as e:
            self.status_label.config(text=f"转换失败！错误: {str(e)}")
            messagebox.showerror("错误", str(e))

    def process_images(self, source_folder, doc, max_width, max_height):
        """处理图片转换过程"""
        image_files = [f for f in os.listdir(source_folder) if f.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp'))]
        
        total = len(image_files)
        if total == 0:
            self.update_status("没有找到任何图片！")
            return
        
        # 增加每行图片数为8张，适合A4横向纸张
        images_per_row = 8
        
        # 创建一个2列的主表格来组织整个文档
        main_table = doc.add_table(rows=1, cols=1)
        main_table.style = 'Table Grid'
        main_table.autofit = False
        
        # 获取主单元格并移除边框
        main_cell = main_table.cell(0, 0)
        # 移除单元格内边距
        tc = main_cell._tc
        tcPr = tc.get_or_add_tcPr()
        
        # 从docx.oxml导入所需功能
        from docx.oxml import parse_xml
        from docx.oxml.ns import nsdecls
        
        # 移除边框和内边距
        tcMar = parse_xml(f'<w:tcMar {nsdecls("w")}>\
            <w:top w:w="0" w:type="dxa"/>\
            <w:left w:w="0" w:type="dxa"/>\
            <w:bottom w:w="0" w:type="dxa"/>\
            <w:right w:w="0" w:type="dxa"/>\
            </w:tcMar>')
        tcPr.append(tcMar)
        
        # 移除表格边框
        from docx.shared import Pt
        
        # 按行组织图片
        row_count = (total + images_per_row - 1) // images_per_row  # 向上取整
        self.update_status(f"共发现 {total} 张图片，将排列为 {row_count} 行，每行 {images_per_row} 张图片")
        
        # 在主单元格中创建内部表格
        for row in range(row_count):
            # 添加一个新段落作为行容器，但第一行不需要
            if row > 0:
                p = main_cell.add_paragraph()
                p.paragraph_format.space_before = Pt(0)
                p.paragraph_format.space_after = Pt(0)
            
            # 创建这一行的表格
            row_table = main_cell.add_table(rows=1, cols=min(images_per_row, total - row * images_per_row))
            row_table.style = 'Table Grid'
            row_table.autofit = False
            
            # 设置行表格的属性
            tbl_pr = row_table._element.xpath('w:tblPr')[0]
            tbl_borders = parse_xml(f'<w:tblBorders {nsdecls("w")}>\
                <w:top w:val="none" w:space="0" w:color="auto"/>\
                <w:left w:val="none" w:space="0" w:color="auto"/>\
                <w:bottom w:val="none" w:space="0" w:color="auto"/>\
                <w:right w:val="none" w:space="0" w:color="auto"/>\
                <w:insideH w:val="none" w:space="0" w:color="auto"/>\
                <w:insideV w:val="none" w:space="0" w:color="auto"/>\
                </w:tblBorders>')
            tbl_pr.append(tbl_borders)
            
            # 处理这一行的图片
            for col in range(min(images_per_row, total - row * images_per_row)):
                index = row * images_per_row + col
                if index < total:
                    image_file = image_files[index]
                    self.update_status(f"正在处理第 {index + 1}/{total} 张图片: {image_file}")
                    image_path = os.path.join(source_folder, image_file)
                    
                    try:
                        # 以适当缩放的尺寸插入图片
                        with Image.open(image_path) as img:
                            width, height = img.size
                            
                            # 显著减小图片尺寸 - 强制缩小至约1/4原始大小
                            # 根据A4横向纸张每行8列，每个单元格约为30mm宽
                            # 30mm = 约85像素(72dpi)
                            target_width = 85
                            scale_ratio = target_width / width
                            
                            # 转换为英寸
                            width_inches = (width * scale_ratio) / 72
                            height_inches = (height * scale_ratio) / 72
                            
                            # 在表格单元格中添加图片
                            cell = row_table.cell(0, col)
                            # 移除单元格内边距
                            cell_tc = cell._tc
                            cell_tcPr = cell_tc.get_or_add_tcPr()
                            cell_tcMar = parse_xml(f'<w:tcMar {nsdecls("w")}>\
                                <w:top w:w="0" w:type="dxa"/>\
                                <w:left w:w="0" w:type="dxa"/>\
                                <w:bottom w:w="0" w:type="dxa"/>\
                                <w:right w:w="0" w:type="dxa"/>\
                                </w:tcMar>')
                            cell_tcPr.append(cell_tcMar)
                            
                            paragraph = cell.paragraphs[0]
                            paragraph.alignment = 1  # 居中对齐
                            run = paragraph.add_run()
                            run.add_picture(image_path, width=Inches(width_inches), height=Inches(height_inches))
                            
                    except Exception as e:
                        self.update_status(f"处理图片 {image_file} 时出错: {e}")
            
            # 更新UI
            self.root.update()

    def save_settings(self):
        """保存当前设置"""
        try:
            settings = {
                'width': float(self.width_entry.get()),
                'height': float(self.height_entry.get())
            }
            with open(self.settings_file, 'w') as f:
                json.dump(settings, f)
        except Exception:
            pass

    def load_settings(self):
        """加载保存的设置"""
        try:
            if os.path.exists(self.settings_file):
                with open(self.settings_file, 'r') as f:
                    settings = json.load(f)
                    self.width_entry.delete(0, tk.END)
                    self.width_entry.insert(0, str(settings.get('width', self.last_width)))
                    self.height_entry.delete(0, tk.END)
                    self.height_entry.insert(0, str(settings.get('height', self.last_height)))
                    self.aspect_ratio = float(settings.get('height', self.last_height)) / float(settings.get('width', self.last_width))
        except Exception:
            pass

    def reset_settings(self):
        """重置为默认设置"""
        self.width_entry.delete(0, tk.END)
        self.width_entry.insert(0, str(self.last_width))
        self.height_entry.delete(0, tk.END)
        self.height_entry.insert(0, str(self.last_height))
        self.aspect_ratio = self.last_height / self.last_width
        self.aspect_var.set(True)
        self.update_status("已重置为默认设置")

    def show_help(self):
        """显示使用说明"""
        help_text = """使用说明：
1. 选择包含图片的文件夹
2. 选择Word文档保存位置
3. 设置图片的最大宽度和高度
4. 点击"开始转换"进行处理

注意事项：
- 支持的图片格式：PNG, JPG, JPEG, GIF, BMP
- 图片尺寸单位为毫米(mm)
- 可以锁定纵横比自动计算尺寸"""
        
        messagebox.showinfo("使用说明", help_text)

    def show_about(self):
        """显示关于信息"""
        about_text = """图片转Word工具
版本：3.0
作者：积极的风筝（堌阳1中）
功能：批量将图片插入Word文档并调整尺寸
"""
        messagebox.showinfo("关于", about_text)

    def on_closing(self):
        """处理窗口关闭事件"""
        try:
            self.save_settings()  # 保存设置
        except:
            pass
        self.root.quit()  # 退出主循环
        self.root.destroy()  # 销毁窗口

def main():
    root = tk.Tk()
    app = ImageToWordApp(root)
    root.mainloop()

if __name__ == "__main__":
    main()